#pragma once
#include "common.h"
#include "GeneratorTester.h"
#include "ResultStorage.h"
#include "Enumerator.h"
#include <string>
#include "Timer.h"

template<class Generator, class Iterator>
class PeriodExplorer
{
public:
	typedef typename SimpleResultStorage<Generator, PeriodAndTail> Storage;
	typedef typename Storage::InvertedTable Table;
	typedef typename Storage::ConfigurationVector ConfigurationVector;

	void explore(Generator *gen, Iterator *it, int seqLength)
	{
		Enumerator<PeriodAndTail, Generator> en(it, seqLength);
		Storage callback;
		en.enumerate(gen, &callback);
		ptable.clear();
		callback.getInvertData(&ptable);
	}
	PeriodAndTail bestPeriodAndTail() const
	{
		return ptable.size() == 0 ? PeriodAndTail() : ptable.rbegin()->first;
	}
	
	const ConfigurationVector bestConfigurations() const
	{
		return ptable.size() == 0 ? ConfigurationVector() : ptable.rbegin()->second;
	}
	
private:
	Table ptable;
};

template<class Generator, class Iterator>
void explorePeriods(Generator *gen, Iterator *it, int seqLength, const std::string &title = "generator")
{
	std::cout << "trying "<< title << "... ";
	PeriodExplorer<Generator, Iterator> e;
	Timer t;
	e.explore(gen, it, seqLength);
	std::cout << "max period: "  << e.bestPeriodAndTail().period
		<< ", tail: " << e.bestPeriodAndTail().tail
		<< ", duration: " << formatTime(t.tickCount()) << "."
		<<  std::endl;
}